home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / Crypt / CHAP.php < prev    next >
PHP Script  |  2004-03-24  |  13KB  |  465 lines

  1. <?php
  2. /*
  3. Copyright (c) 2002-2003, Michael Bretterklieber <michael@bretterklieber.com>
  4. All rights reserved.
  5.  
  6. Redistribution and use in source and binary forms, with or without 
  7. modification, are permitted provided that the following conditions 
  8. are met:
  9.  
  10. 1. Redistributions of source code must retain the above copyright 
  11.    notice, this list of conditions and the following disclaimer.
  12. 2. Redistributions in binary form must reproduce the above copyright 
  13.    notice, this list of conditions and the following disclaimer in the 
  14.    documentation and/or other materials provided with the distribution.
  15. 3. The names of the authors may not be used to endorse or promote products 
  16.    derived from this software without specific prior written permission.
  17.  
  18. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
  19. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
  20. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
  21. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
  22. INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
  23. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
  24. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
  25. OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
  26. NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
  27. EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28.  
  29. This code cannot simply be copied and put under the GNU Public License or 
  30. any other GPL-like (LGPL, GPL2) License.
  31.  
  32.     $Id: CHAP.php,v 1.5 2004/03/25 15:39:32 mbretter Exp $
  33. */
  34.  
  35. require_once 'PEAR.php';
  36.  
  37. /**
  38. * Classes for generating packets for various CHAP Protocols:
  39. * CHAP-MD5: RFC1994
  40. * MS-CHAPv1: RFC2433
  41. * MS-CHAPv2: RFC2759
  42. *
  43. * @package Crypt_CHAP
  44. * @author  Michael Bretterklieber <michael@bretterklieber.com>
  45. * @access  public
  46. * @version $Revision: 1.5 $
  47. */
  48.  
  49. /**
  50.  * class Crypt_CHAP
  51.  *
  52.  * Abstract base class for CHAP
  53.  *
  54.  * @package Crypt_CHAP 
  55.  */
  56. class Crypt_CHAP extends PEAR 
  57. {
  58.     /**
  59.      * Random binary challenge
  60.      * @var  string
  61.      */
  62.     var $challenge = null;
  63.  
  64.     /**
  65.      * Binary response
  66.      * @var  string
  67.      */
  68.     var $response = null;    
  69.  
  70.     /**
  71.      * User password
  72.      * @var  string
  73.      */
  74.     var $password = null;
  75.  
  76.     /**
  77.      * Id of the authentication request. Should incremented after every request.
  78.      * @var  integer
  79.      */
  80.     var $chapid = 1;
  81.     
  82.     /**
  83.      * Constructor
  84.      *
  85.      * Generates a random challenge
  86.      * @return void
  87.      */
  88.     function Crypt_CHAP()
  89.     {
  90.         $this->PEAR();
  91.         $this->generateChallenge();
  92.     }
  93.     
  94.     /**
  95.      * Generates a random binary challenge
  96.      *
  97.      * @param  string  $varname  Name of the property
  98.      * @param  integer $size     Size of the challenge in Bytes
  99.      * @return void
  100.      */
  101.     function generateChallenge($varname = 'challenge', $size = 8)
  102.     {
  103.         $this->$varname = '';
  104.         mt_srand(hexdec(substr(md5(microtime()), -8)) & 0x7fffffff);
  105.         for ($i = 0; $i < $size; $i++) {
  106.             $this->$varname .= pack('C', 1 + mt_rand() % 255);
  107.         }
  108.         return $this->$varname;
  109.     }
  110.  
  111.     /**
  112.      * Generates the response. Overwrite this.
  113.      *
  114.      * @return void
  115.      */    
  116.     function challengeResponse()
  117.     {
  118.     }
  119.         
  120. }
  121.  
  122. /**
  123.  * class Crypt_CHAP_MD5
  124.  *
  125.  * Generate CHAP-MD5 Packets
  126.  *
  127.  * @package Crypt_CHAP 
  128.  */
  129. class Crypt_CHAP_MD5 extends Crypt_CHAP 
  130. {
  131.  
  132.     /**
  133.      * Generates the response.
  134.      *
  135.      * CHAP-MD5 uses MD5-Hash for generating the response. The Hash consists
  136.      * of the chapid, the plaintext password and the challenge.
  137.      *
  138.      * @return string
  139.      */ 
  140.     function challengeResponse()
  141.     {
  142.         return pack('H*', md5(pack('C', $this->chapid) . $this->password . $this->challenge));
  143.     }
  144. }
  145.  
  146. /**
  147.  * class Crypt_CHAP_MSv1
  148.  *
  149.  * Generate MS-CHAPv1 Packets. MS-CHAP doesen't use the plaintext password, it uses the
  150.  * NT-HASH wich is stored in the SAM-Database or in the smbpasswd, if you are using samba.
  151.  * The NT-HASH is MD4(str2unicode(plaintextpass)). 
  152.  * You need the mhash extension for this class.
  153.  * 
  154.  * @package Crypt_CHAP 
  155.  */
  156. class Crypt_CHAP_MSv1 extends Crypt_CHAP
  157. {
  158.     /**
  159.      * Wether using deprecated LM-Responses or not.
  160.      * 0 = use LM-Response, 1 = use NT-Response
  161.      * @var  bool
  162.      */
  163.     var $flags = 1;
  164.     
  165.     /**
  166.      * Constructor
  167.      *
  168.      * Loads the mhash extension
  169.      * @return void
  170.      */
  171.     function Crypt_CHAP_MSv1()
  172.     {
  173.         $this->Crypt_CHAP();
  174.         $this->loadExtension('mhash');        
  175.     }
  176.     
  177.     /**
  178.      * Generates the NT-HASH from the given plaintext password.
  179.      *
  180.      * @access public
  181.      * @return string
  182.      */
  183.     function ntPasswordHash($password = null) 
  184.     {
  185.         if (isset($password)) {
  186.             return mhash(MHASH_MD4, $this->str2unicode($password));
  187.         } else {
  188.             return mhash(MHASH_MD4, $this->str2unicode($this->password));
  189.         }
  190.     }
  191.     
  192.     /**
  193.      * Converts ascii to unicode.
  194.      *
  195.      * @access public
  196.      * @return string
  197.      */
  198.     function str2unicode($str) 
  199.     {
  200.         $uni = '';
  201.         $str = (string) $str;
  202.         for ($i = 0; $i < strlen($str); $i++) {
  203.             $a = ord($str{$i}) << 8;
  204.             $uni .= sprintf("%X", $a);
  205.         }
  206.         return pack('H*', $uni);
  207.     }    
  208.     
  209.     /**
  210.      * Generates the NT-Response. 
  211.      *
  212.      * @access public
  213.      * @return string
  214.      */  
  215.     function challengeResponse() 
  216.     {
  217.         return $this->_challengeResponse();
  218.     }
  219.     
  220.     /**
  221.      * Generates the NT-Response. 
  222.      *
  223.      * @access public
  224.      * @return string
  225.      */  
  226.     function ntChallengeResponse() 
  227.     {
  228.         return $this->_challengeResponse(false);
  229.     }    
  230.     
  231.     /**
  232.      * Generates the LAN-Manager-Response. 
  233.      *
  234.      * @access public
  235.      * @return string
  236.      */
  237.     function lmChallengeResponse()
  238.     {
  239.         return $this->_challengeResponse(true);
  240.     }
  241.  
  242.     /**
  243.      * Generates the response.
  244.      *
  245.      * Generates the response using DES.
  246.      *
  247.      * @param  bool  $lm  wether generating LAN-Manager-Response
  248.      * @access private
  249.      * @return string
  250.      */
  251.     function _challengeResponse($lm = false)
  252.     {
  253.         if ($lm) {
  254.             $hash = $this->lmPasswordHash();
  255.         } else {
  256.             $hash = $this->ntPasswordHash();
  257.         }
  258.  
  259.         while (strlen($hash) < 21) {
  260.             $hash .= "\0";
  261.         }
  262.  
  263.         $td = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, '');
  264.         $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
  265.         $key = $this->_desAddParity(substr($hash, 0, 7));
  266.         mcrypt_generic_init($td, $key, $iv);
  267.         $resp1 = mcrypt_generic($td, $this->challenge);
  268.         mcrypt_generic_deinit($td);
  269.  
  270.         $key = $this->_desAddParity(substr($hash, 7, 7));
  271.         mcrypt_generic_init($td, $key, $iv);
  272.         $resp2 = mcrypt_generic($td, $this->challenge);
  273.         mcrypt_generic_deinit($td);
  274.  
  275.         $key = $this->_desAddParity(substr($hash, 14, 7));
  276.         mcrypt_generic_init($td, $key, $iv);
  277.         $resp3 = mcrypt_generic($td, $this->challenge);
  278.         mcrypt_generic_deinit($td);
  279.         mcrypt_module_close($td);
  280.  
  281.         return $resp1 . $resp2 . $resp3;
  282.     }
  283.  
  284.     /**
  285.      * Generates the LAN-Manager-HASH from the given plaintext password.
  286.      *
  287.      * @access public
  288.      * @return string
  289.      */
  290.     function lmPasswordHash($password = null)
  291.     {
  292.         $plain = isset($password) ? $password : $this->password;
  293.  
  294.         $plain = substr(strtoupper($plain), 0, 14);
  295.         while (strlen($plain) < 14) {
  296.              $plain .= "\0";
  297.         }
  298.  
  299.         return $this->_desHash(substr($plain, 0, 7)) . $this->_desHash(substr($plain, 7, 7));
  300.     }
  301.  
  302.     /**
  303.      * Generates an irreversible HASH.
  304.      *
  305.      * @access private
  306.      * @return string
  307.      */
  308.     function _desHash($plain)
  309.     {
  310.         $key = $this->_desAddParity($plain);
  311.         $td = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, '');
  312.         $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
  313.         mcrypt_generic_init($td, $key, $iv);
  314.         $hash = mcrypt_generic($td, 'KGS!@#$%');
  315.         mcrypt_generic_deinit($td);
  316.         mcrypt_module_close($td);
  317.         return $hash;
  318.     }
  319.  
  320.     /**
  321.      * Adds the parity bit to the given DES key.
  322.      *
  323.      * @access private
  324.      * @param  string  $key 7-Bytes Key without parity
  325.      * @return string
  326.      */
  327.     function _desAddParity($key)
  328.     {
  329.         static $odd_parity = array(
  330.                 1,  1,  2,  2,  4,  4,  7,  7,  8,  8, 11, 11, 13, 13, 14, 14,
  331.                 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
  332.                 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
  333.                 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
  334.                 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
  335.                 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
  336.                 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,
  337.                 112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
  338.                 128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,
  339.                 145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
  340.                 161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
  341.                 176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,
  342.                 193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
  343.                 208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
  344.                 224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
  345.                 241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254);
  346.  
  347.         $bin = '';
  348.         for ($i = 0; $i < strlen($key); $i++) {
  349.             $bin .= sprintf('%08s', decbin(ord($key{$i})));
  350.         }
  351.  
  352.         $str1 = explode('-', substr(chunk_split($bin, 7, '-'), 0, -1));
  353.         $x = '';
  354.         foreach($str1 as $s) {
  355.             $x .= sprintf('%02s', dechex($odd_parity[bindec($s . '0')]));
  356.         }
  357.  
  358.         return pack('H*', $x);
  359.  
  360.     }
  361.     
  362.     /**
  363.      * Generates the response-packet. 
  364.      *
  365.      * @param  bool  $lm  wether including LAN-Manager-Response
  366.      * @access private
  367.      * @return string
  368.      */      
  369.     function response($lm = false)
  370.     {
  371.         $ntresp = $this->ntChallengeResponse();
  372.         if ($lm) {
  373.             $lmresp = $this->lmChallengeResponse();
  374.         } else {
  375.             $lmresp = str_repeat ("\0", 24);
  376.         }
  377.  
  378.         // Response: LM Response, NT Response, flags (0 = use LM Response, 1 = use NT Response)
  379.         return $lmresp . $ntresp . pack('C', !$lm);
  380.     }
  381. }
  382.  
  383. /**
  384.  * class Crypt_CHAP_MSv2
  385.  *
  386.  * Generate MS-CHAPv2 Packets. This version of MS-CHAP uses a 16 Bytes authenticator 
  387.  * challenge and a 16 Bytes peer Challenge. LAN-Manager responses no longer exists
  388.  * in this version. The challenge is already a SHA1 challenge hash of both challenges 
  389.  * and of the username.
  390.  * 
  391.  * @package Crypt_CHAP 
  392.  */
  393. class Crypt_CHAP_MSv2 extends Crypt_CHAP_MSv1
  394. {
  395.     /**
  396.      * The username
  397.      * @var  string
  398.      */
  399.     var $username = null;
  400.  
  401.     /**
  402.      * The 16 Bytes random binary peer challenge
  403.      * @var  string
  404.      */
  405.     var $peerChallenge = null;
  406.  
  407.     /**
  408.      * The 16 Bytes random binary authenticator challenge
  409.      * @var  string
  410.      */
  411.     var $authChallenge = null;
  412.     
  413.     /**
  414.      * Constructor
  415.      *
  416.      * Generates the 16 Bytes peer and authentication challenge
  417.      * @return void
  418.      */
  419.     function Crypt_CHAP_MSv2()
  420.     {
  421.         $this->Crypt_CHAP_MSv1();
  422.         $this->generateChallenge('peerChallenge', 16);
  423.         $this->generateChallenge('authChallenge', 16);
  424.     }    
  425.  
  426.     /**
  427.      * Generates a hash from the NT-HASH.
  428.      *
  429.      * @access public
  430.      * @param  string  $nthash The NT-HASH
  431.      * @return string
  432.      */    
  433.     function ntPasswordHashHash($nthash) 
  434.     {
  435.         return mhash(MHASH_MD4, $nthash);
  436.     }
  437.     
  438.     /**
  439.      * Generates the challenge hash from the peer and the authenticator challenge and
  440.      * the username. SHA1 is used for this, but only the first 8 Bytes are used.
  441.      *
  442.      * @access public
  443.      * @return string
  444.      */   
  445.     function challengeHash() 
  446.     {
  447.         return substr(mhash(MHASH_SHA1, $this->peerChallenge . $this->authChallenge . $this->username), 0, 8);
  448.     }    
  449.  
  450.     /**
  451.      * Generates the response. 
  452.      *
  453.      * @access public
  454.      * @return string
  455.      */  
  456.     function challengeResponse() 
  457.     {
  458.         $this->challenge = $this->challengeHash();
  459.         return $this->_challengeResponse();
  460.     }    
  461. }
  462.  
  463.  
  464. ?>
  465.